import { Button, Input, Space } from "antd";
import styles from "./Eval.module.css";
import { useEffect, useRef, useState } from "react";
import { copyText } from "../../../../utils/common/copy";
import React from "react";
import { snippetApi } from "../../../../utils/backend/server";
import GoBackHeader from "../../../../components/GoBackHeader";

// ../Engine/Engine.tsx
export interface SnippetType {
  id: number;
  content: string;
}

type SnippetVoType = SnippetType & {
  type: "old" | "new";
};

const template = `


return e;`;

export default (): JSX.Element => {
  const [snippetList, setSnippetList] = useState<SnippetVoType[]>([]);
  const [res, setRes] = useState<string>("");
  const [clipboardText, setClipboardText] = useState("");
  const [visibilitychange, setVisibilitychange] = useState<boolean>(false);

  const refresh = () => {
    snippetApi.getSnippetList().then((list) => {
      setSnippetList((val) => [
        ...list.map((val) => ({ ...val, type: "old" as "old" })),
        ...val.filter((item) => item.type === "new"),
      ]);
    });
  };

  useEffect(() => {
    refresh();

    const handleFocus = () => {
      navigator.clipboard.readText().then((res) => {
        setClipboardText(res);
      });
      setVisibilitychange((val) => !val);
    };

    window.addEventListener("visibilitychange", handleFocus);

    return () => {
      window.removeEventListener("visibilitychange", handleFocus);
    };
  }, []);

  return (
    <>
      <GoBackHeader />
      <div className={styles.box}>
        {snippetList.map((val) => (
          <div key={val.id}>
            <EvalItem
              item={val}
              defaultText={val.content}
              remove={(e) => {
                if (e.type === "old") {
                  snippetApi.removeSnippet(e.id).then(() => {
                    refresh();
                  });
                } else {
                  setSnippetList((val) =>
                    val.filter((item) => item.id !== e.id)
                  );
                }
              }}
              setResult={(e) => {
                setRes(e);
                navigator.clipboard.writeText(e);
              }}
              update={(e) => setClipboardText(e)}
              save={(e) => {
                if (e.type === "old") {
                  snippetApi.updateSnippet(e);
                } else {
                  snippetApi.addSnippet(e);
                }
              }}
              visibilitychange={visibilitychange}
            />
          </div>
        ))}

        <Button
          type="primary"
          onClick={() => {
            setSnippetList((old) => [
              ...old,
              { id: new Date().valueOf(), content: template, type: "new" },
            ]);
          }}
        >
          add
        </Button>
        <div style={{ marginTop: "20px" }}>
          <h3>tips:</h3>
          <span>
            the function you provide, must accept clipboard text as parameter, and
            return values that is text format
          </span>
        </div>
        <div style={{ marginTop: "20px" }}>
          <h3 onClick={() => copyText(clipboardText)}>Result:</h3>
          <p>{clipboardText}</p>
          <p>-----------------------------------------------</p>
          <p>{res}</p>
        </div>
      </div>
    </>
  );
};

const EvalItem = (props: {
  item: SnippetVoType;
  save: (val: SnippetVoType) => void;
  remove: (val: SnippetVoType) => void;
  setResult: (val: string) => void;
  update: (val: string) => void;
  defaultText: string;
  visibilitychange: boolean;
}): JSX.Element => {
  const { TextArea } = Input;
  const [customInput, setCustomInput] = useState<string>("");
  const [text, setText] = useState(props.defaultText);
  const textRef = useRef(null);

  const evalJs = (res: string) => {
    props.setResult(eval("let foo = (e) =>{" + text + "}; foo(`" + res + "`)"));
    props.update(res);
  };

  useEffect(() => {
    setCustomInput("");
  }, [props.visibilitychange]);

  return (
    <div className={styles.evalItem}>
      <Space.Compact block direction="vertical">
        <Space>
          <Input
            value={customInput}
            onChange={(e) => setCustomInput(e.target.value)}
          />
          &nbsp; e =&gt;
        </Space>
        <TextArea
          rows={8}
          value={text}
          onChange={(e) => setText(e.target.value)}
          ref={textRef}
        />
        <Space>
          <Button
            type="primary"
            onClick={() => {
              if ("" !== customInput) {
                evalJs(customInput);
                return;
              }
              navigator.clipboard.readText().then(evalJs);
            }}
          >
            execute
          </Button>
          <Button
            onClick={() => {
              setText(template);
              textRef.current && (textRef.current as HTMLInputElement).focus();
            }}
          >
            clear
          </Button>
          <Button onClick={() => props.remove(props.item)}>remove</Button>
          <Button
            onClick={() => {
              const newItem = {
                ...props.item,
                content: text,
              };
              props.save(newItem);
            }}
          >
            save
          </Button>
        </Space>
      </Space.Compact>
    </div>
  );
};